{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "28d2fb105496daae",
   "metadata": {},
   "source": [
    "## 0.引言\n",
    "在深度学习网络构建与计算过程中，我们经常会使用到张量维度之间的各种转换，用于不同操作。Pytorch中常见的维度转换函数有view，reshape，permute，flatten。本文将详细介绍这几个函数的作用与使用方式，并给出了具体的代码示例，希望能够帮助大家。\n",
    "\n",
    "常见的维度有四维：比如（batch, channel, height, width）；三维：比如（b,n,c）；二维：比如（h,w）。下面介绍如何使用上述函数进行维度之间的转换。\n",
    "\n",
    "## 1.view函数\n",
    "### 作用\n",
    "\n",
    "tensor.view() 可以用来调整张量的形状，这对于在网络层之间传递数据或者在处理图像数据时非常有用。需要注意的是，新的形状必须与原始张量的元素数量一致。\n",
    "\n",
    "### 参数\n",
    "\n",
    "size (tuple of ints) – 新的大小应该与原张量元素数量相匹配。可以指定一个尺寸为 -1 的维度来自动计算合适的大小。\n",
    "\n",
    "### 代码示例\n",
    "```python\n",
    "import torch\n",
    "# view使用示例\n",
    "x = torch.randn(16,3,64,64) # B, C, H, W\n",
    "print(x.shape) #torch.Size([16,3,64,64])\n",
    "B, C, H, W = x.size()\n",
    " \n",
    "# 转为BNC\n",
    "x = x.view(B, -1, C)\n",
    "# 或者 x = x.view(B, H*W, C)\n",
    "print(x.shape) #torch.Size([16, 4096, 3])\n",
    "```\n",
    "将计算机视觉中的常见四维张量（Batch, Channel, Height, Width）转为三维（Batch，N，Channel）形式。\n",
    "\n",
    "torch.randn() 是 PyTorch 中的一个函数，用于生成一个填充了从标准正态分布（均值为 0，方差为 1）中随机抽取的数字的张量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4dbcd6107d73d37d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-22T09:30:09.463415Z",
     "start_time": "2024-11-22T09:30:09.453114Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([16, 3, 64, 64])\n",
      "torch.Size([16, 4096, 3])\n"
     ]
    }
   ],
   "source": [
    "\n",
    "import torch\n",
    "# view使用示例\n",
    "x = torch.randn(16,3,64,64) # B, C, H, W\n",
    "print(x.shape) #torch.Size([16,3,64,64])\n",
    "B, C, H, W = x.size()\n",
    " \n",
    "# 转为BNC\n",
    "x = x.view(B, -1, C)\n",
    "# 或者 x = x.view(B, H*W, C)\n",
    "print(x.shape) #torch.Size([16, 4096, 3])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7931e5641e52700",
   "metadata": {},
   "source": [
    "## 2.permute函数\n",
    "作用permute() 函数用于改变张量的维度顺序。它接受一个新的维度顺序作为参数，并返回一个新的张量，其维度顺序按照给定的顺序排列。参数说明参数：一个元组，表示新的维度顺序。例如，对于一个形状为 (10, 3, 32, 32) 的张量，permute(0, 2, 3, 1) 表示新的维度顺序为 (10, 32, 32, 3)。其中0,1,2,3分别表示4个维度(10, 3, 32, 32)的索引。\n",
    "\n",
    "### 代码示例\n",
    "\n",
    "依然将计算机视觉中的常见四维张量（Batch, Channel, Height, Width）转为三维（Batch，N，Channel）形式。\n",
    "```python\n",
    "import torch\n",
    "# permute使用示例：permute转换唯独顺序\n",
    "x = torch.randn(16,3,64,64) # B, C, H, W\n",
    "print(x.shape) #torch.Size([16,3,64,64])\n",
    " \n",
    "# 16,3,64,64的维度索引分别为0，1，2，3\n",
    "dim_change = x.permute(0,2,3,1) # 转为 B,H，W，C\n",
    "# 然后将中间两个通道索引为[1,2]展平\n",
    "out = dim_change.flatten(start_dim=1,end_dim=2)\n",
    "print(out.shape) #torch.Size([16, 4096, 3])\n",
    "```\n",
    "flatten() 方法用于展平张量的一个或多个维度。它可以接受两个可选参数：start_dim：从哪个维度开始展平，默认为 0。 \n",
    "\n",
    "end_dim：到哪个维度结束展平，默认为 -1，表示直到最后一个维度。 \n",
    "\n",
    "此处的作用是将第二个和第三个维度进行展平。start_dim=1 表示从第二个维度（即 64）开始展平。end_dim=2 表示到第三个维度（即 64）结束展平。展平后的结果为 (16, 4096, 3)，其中 4096= 64 * 64。 \n",
    "\n",
    "通过这些步骤，你可以将原始张量从 (16,3,64,64) 转换为 (16, 4096, 3)。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5228146766764b83",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-22T09:31:02.188338Z",
     "start_time": "2024-11-22T09:31:02.177861Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([16, 3, 64, 64])\n",
      "torch.Size([16, 4096, 3])\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "# permute使用示例：permute转换唯独顺序\n",
    "x = torch.randn(16,3,64,64) # B, C, H, W\n",
    "print(x.shape) #torch.Size([16,3,64,64])\n",
    " \n",
    "# 16,3,64,64的维度索引分别为0，1，2，3\n",
    "dim_change = x.permute(0,2,3,1) # 转为 B,H，W，C\n",
    "# 然后将中间两个通道索引为[1,2]展平\n",
    "out = dim_change.flatten(start_dim=1,end_dim=2)\n",
    "print(out.shape) #torch.Size([16, 4096, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fef293dc82fd23a0",
   "metadata": {},
   "source": [
    "\n",
    "### 3.Reshape函数\n",
    "torch.reshape() 可以改变张量的形状，而不改变张量中的数据。与view函数的作用类似。注意事项:新旧形状的元素总数必须相同。\n",
    "\n",
    " \n",
    "```python\n",
    "import torch\n",
    " \n",
    "# 创建一个简单的张量\n",
    "x = torch.randn(4, 3)\n",
    "print(\"Original tensor:\")\n",
    "print(x)\n",
    " \n",
    "# 使用 torch.reshape() 来改变张量的形状\n",
    "# 将 (4, 3) 的张量转换成 (2, 6) 的张量\n",
    "reshaped_x = torch.reshape(x, (2, 6))\n",
    "print(\"\\nReshaped tensor:\")\n",
    "print(reshaped_x)\n",
    " \n",
    "# 如果不确定某个维度的大小，可以使用 -1 让 PyTorch 自动计算\n",
    "# 这里将 (4, 3) 转换为 (12,) 的一维张量\n",
    "flat_x = torch.reshape(x, (-1))\n",
    "print(\"\\nFlattened tensor:\")\n",
    "print(flat_x)\n",
    " \n",
    "# 更复杂的形状变换\n",
    "# 将 (4, 3) 转换为 (3, 4) 的张量\n",
    "complex_reshaped_x = torch.reshape(x, (3, 4))\n",
    "print(\"\\nComplex reshaped tensor:\")\n",
    "print(complex_reshaped_x)\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "b65145e2ed470d42",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-22T09:32:08.273258Z",
     "start_time": "2024-11-22T09:32:08.262335Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original tensor:\n",
      "tensor([[-2.0359, -0.0563, -2.1975],\n",
      "        [-0.4843, -0.0362, -1.5339],\n",
      "        [ 0.2994,  1.3199, -0.3768],\n",
      "        [-1.6559,  2.3600, -1.1901]])\n",
      "\n",
      "Reshaped tensor:\n",
      "tensor([[-2.0359, -0.0563, -2.1975, -0.4843, -0.0362, -1.5339],\n",
      "        [ 0.2994,  1.3199, -0.3768, -1.6559,  2.3600, -1.1901]])\n",
      "\n",
      "Flattened tensor:\n",
      "tensor([-2.0359, -0.0563, -2.1975, -0.4843, -0.0362, -1.5339,  0.2994,  1.3199,\n",
      "        -0.3768, -1.6559,  2.3600, -1.1901])\n",
      "\n",
      "Complex reshaped tensor:\n",
      "tensor([[-2.0359, -0.0563, -2.1975, -0.4843],\n",
      "        [-0.0362, -1.5339,  0.2994,  1.3199],\n",
      "        [-0.3768, -1.6559,  2.3600, -1.1901]])\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    " \n",
    "# 创建一个简单的张量\n",
    "x = torch.randn(4, 3)\n",
    "print(\"Original tensor:\")\n",
    "print(x)\n",
    " \n",
    "# 使用 torch.reshape() 来改变张量的形状\n",
    "# 将 (4, 3) 的张量转换成 (2, 6) 的张量\n",
    "reshaped_x = torch.reshape(x, (2, 6))\n",
    "print(\"\\nReshaped tensor:\")\n",
    "print(reshaped_x)\n",
    " \n",
    "# 如果不确定某个维度的大小，可以使用 -1 让 PyTorch 自动计算\n",
    "# 这里将 (4, 3) 转换为 (12,) 的一维张量\n",
    "flat_x = torch.reshape(x, [-1])\n",
    "print(\"\\nFlattened tensor:\")\n",
    "print(flat_x)\n",
    " \n",
    "# 更复杂的形状变换\n",
    "# 将 (4, 3) 转换为 (3, 4) 的张量\n",
    "complex_reshaped_x = torch.reshape(x, (3, 4))\n",
    "print(\"\\nComplex reshaped tensor:\")\n",
    "print(complex_reshaped_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f46dce7d90c541d",
   "metadata": {},
   "source": [
    "## 4.flatten函数\n",
    "torch.flatten 是 PyTorch 库中的一个函数，用于将一个多维张量转换为一维张量或降低其维度。\n",
    "\n",
    "### torch.flatten参数说明\n",
    "\n",
    "- input: 这是要被展平的张量。这是必需的参数。 \n",
    "\n",
    "- start_dim (可选): 指定从哪个维度开始展平。默认值为 0，这意味着展平将从第一个维度（通常是批量大小）开始。如果你希望保留前几个维度并只展平后续的维度，你可以设置这个参数。 \n",
    "\n",
    "- end_dim (可选): 指定展平到哪个维度结束。默认值为 -1，这表示展平将一直持续到最后一个维度。如果只想展平中间的一部分维度，可以设置这个参数来指定结束维度。\n",
    "\n",
    "当 start_dim 和 end_dim 都没有被显式地指定时，torch.flatten 将会展平除了第一个维度之外的所有维度，通常第一个维度是批量大小，会被保留以便于批次处理。\n",
    "\n",
    "### 代码示例\n",
    "\n",
    "举个例子，假设你有一个形状为 [batch_size, channels, height, width] 的四维张量，如果你想将其展平为 [batch_size, channels * height * width] 的二维张量，你可以直接调用 torch.flatten 而不需要额外的参数。但是，如果你想保留通道维度，并展平高度和宽度维度，你可以设置 start_dim=1 和 end_dim=2。\n",
    "```pyton\n",
    "import torch\n",
    " \n",
    "# 创建一个形状为 [8, 3, 64, 64] 的随机张量\n",
    "x = torch.randn(8, 3, 64, 64)\n",
    " \n",
    "# 展平除了第一个维度外的所有维度\n",
    "y = torch.flatten(x)\n",
    "print(y.shape)  # 输出: torch.Size([8, 12288])\n",
    " \n",
    "# 只展平第二和第三个维度[也就是最后两个维度],0,1,2,3\n",
    "z = torch.flatten(x, 1, 2)\n",
    "print(z.shape)  # 输出: torch.Size([8, 3, 4096])\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "6483135726ef5f78",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-22T09:32:27.082636Z",
     "start_time": "2024-11-22T09:32:27.074734Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([98304])\n",
      "torch.Size([8, 192, 64])\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    " \n",
    "# 创建一个形状为 [8, 3, 64, 64] 的随机张量\n",
    "x = torch.randn(8, 3, 64, 64)\n",
    " \n",
    "# 展平除了第一个维度外的所有维度\n",
    "y = torch.flatten(x)\n",
    "print(y.shape)  # 输出: torch.Size([8, 12288])\n",
    " \n",
    "# 只展平第二和第三个维度[也就是最后两个维度],0,1,2,3\n",
    "z = torch.flatten(x, 1, 2)\n",
    "print(z.shape)  # 输出: torch.Size([8, 3, 4096])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
